module test_verlet_m

    use testdrive, only: new_unittest, unittest_type, error_type, check
    use verlet_m
    implicit none
    private

    public :: collect_verlet

contains

    !> Collect all exported unit tests
    subroutine collect_verlet(testsuite)
        !> Collection of tests
        type(unittest_type), allocatable, intent(out) :: testsuite(:)

        testsuite = [ &
                    new_unittest("SUB: velocity_verlet", test_velocity_verlet), &
                    new_unittest("SUB: leap_frog", test_leap_frog) &
                    ]

    end subroutine collect_verlet

    subroutine test_velocity_verlet(error)
        type(error_type), allocatable, intent(out) :: error
        integer, parameter :: nstep = 2
        real :: t(nstep), y(nstep, 1), v(nstep, 1), a(nstep, 1)

        call velocity_verlet(fcn, [0.0, 1.0], [0.0], [0.0], t, y, v, a)
        call check(error, t(1), 0.0, "t(1)")
        if (allocated(error)) return
        call check(error, t(nstep), 1.0, "t(nstep)")
        if (allocated(error)) return

        call check(error, y(1, 1), 0.0, "y(1)")
        if (allocated(error)) return
        call check(error, y(nstep, 1), -4.90, "y(nstep)")
        if (allocated(error)) return

        call check(error, v(1, 1), 0.0, "v(1)")
        if (allocated(error)) return
        call check(error, v(nstep, 1), -9.80, "v(nstep)")
        if (allocated(error)) return

        call check(error, a(1, 1), -9.80, "a(1)")
        if (allocated(error)) return
        call check(error, a(nstep, 1), -9.80, "a(nstep)")

    contains

        pure subroutine fcn(y, a)
            real, intent(in) :: y(:)   !! 位置
            real, intent(out) :: a(:)  !! 加速度
            a = -9.8
        end subroutine fcn

    end subroutine test_velocity_verlet
    
    subroutine test_leap_frog(error)
        type(error_type), allocatable, intent(out) :: error
        integer, parameter :: nstep = 2
        real :: t(nstep), y(nstep, 1), v(nstep, 1), a(nstep, 1)

        call leap_frog(fcn, [0.0, 1.0], [0.0], [0.0], t, y, v, a, .true.)
        call check(error, t(1), 0.0, "t(1)")
        if (allocated(error)) return
        call check(error, t(nstep), 1.0, "t(nstep)")
        if (allocated(error)) return

        call check(error, y(1, 1), 0.0, "y(1)")
        if (allocated(error)) return
        call check(error, y(nstep, 1), -4.90, "y(nstep)")
        if (allocated(error)) return

        call check(error, v(1, 1), 0.0, "v(1)")
        if (allocated(error)) return
        call check(error, v(nstep, 1), -9.80, "v(nstep)")
        if (allocated(error)) return

        call check(error, a(1, 1), -9.80, "a(1)")
        if (allocated(error)) return
        call check(error, a(nstep, 1), -9.80, "a(nstep)")

    contains

        pure subroutine fcn(y, v, a)
            real, intent(in) :: y(:)   !! 位置
            real, intent(in) :: v(:)   !! 速度
            real, intent(out) :: a(:)  !! 加速度
            a = -9.8
        end subroutine fcn

    end subroutine test_leap_frog

end module test_verlet_m
